﻿using System;
using System.Collections.Generic;
using System.Linq;

namespace com.susi.util
{
    public static class DictionaryExtensions
    {

        /// <summary>
        /// 如果没有里表，会自动创建
        /// <para>不会对dic判空</para>
        /// </summary>
        public static void AddToInnerList<TKey, TItem,TCollection>
            (this IDictionary<TKey, TCollection> dic, TKey key, TItem item)
            where TCollection:ICollection<TItem>,new()
        {
            if (!dic.ContainsKey(key)) dic.Add(key, new TCollection());
            if (dic[key] == null)
            {
                dic[key] = new TCollection();
            }
            dic[key].Add(item);
        }

        /// <summary>
        /// 如果没有里表，会自动创建
        /// <para>不会对dic\items判空</para>
        /// </summary>
        public static void AddToInnerList<TKey, TItem, TCollection>
            (this IDictionary<TKey, TCollection> dic, TKey key, IEnumerable<TItem> items)
            where TCollection : ICollection<TItem>, new()
        {
            if (!dic.ContainsKey(key)) dic.Add(key, new TCollection());
            if (dic[key] == null)
            {
                dic[key] = new TCollection();
            }
            foreach (var i in items) dic[key].Add(i);
        }

        /// <summary>
        /// 如果没有里表，会自动创建
        /// </summary>
        public static void AddToInnerList<TKey, TItem, TCollection>
            (this IDictionary<TKey, TCollection> dic, TKey key, TItem item,Func<TCollection> LCreater) 
            where TCollection : ICollection<TItem>
        {
            if (!dic.ContainsKey(key)) dic.Add(key, LCreater());
            if (dic[key] == null)
            {
                dic[key] = LCreater();
            }
            dic[key].Add(item);
        }

        /// <summary>
        /// 移除里表物体后，里表为空时保留空里表
        /// </summary>
        public static bool RemoveFromInnerList<Key, T,L>(this IDictionary<Key, L> dic, Key key, T item)
            where L:ICollection<T>
        {
            if (dic.TryGetValue(key, out var lst)) {
                return lst != null && lst.Remove(item);
            }
            else return false;
        }

        /// <summary>
        /// 移除里表物体后，里表为空时删除key
        /// </summary>
        public static bool RemoveFromInnerListAndTrim<Key, T, L>(this IDictionary<Key, L> dic, Key key, T item) 
            where L : ICollection<T>
        {
            if (dic.TryGetValue(key, out var lst))
            {
                if (lst == null) return false;
                var res = lst.Remove(item);
                if (lst.Count == 0)
                {
                    dic.Remove(key);
                    (lst as IDisposable)?.Dispose();
                }
                return res;
            }
            else return false;
        }
        
        /// <summary>
        /// 获取所有里表字典的表项，自动排除null项
        /// <para>如果dic为null则返回一个没有元素的遍历体</para>
        /// </summary>
        [Obsolete]
        public static IEnumerable<TItem> SelectAllChildrenWithOutNull<TKey, TIEnumerable,TItem>
            (this IDictionary<TKey, TIEnumerable> dic)
            where TIEnumerable:IEnumerable<TItem>
        {
            if(dic==null)return Enumerable.Empty<TItem>();
            return (from lst in dic.Values
                where lst != null
                from item in lst
                select item);
        }
        
        /// <summary>
        /// 获取所有里表字典的表项，自动排除null
        /// <para>如果dic为null则返回一个没有元素的遍历体</para>
        /// </summary>
        //数组不支持翻译为IEnumerable故需要这个函数
        [Obsolete]
        public static IEnumerable<T> SelectAllChildrenWithOutNull<Key, T>(this IDictionary<Key, T[]> dic)
        {
            if(dic==null)return Enumerable.Empty<T>();
            return (from lst in dic.Values
                where lst!=null
                from item in lst
                select item);
        }
        
        #region about add
        public static bool AddOrReplaceKV<K, V>(this IDictionary<K, V> dic, K key, V value)
        {
            if (dic.ContainsKey(key))
            {
                dic[key] = value;
                return false;
            }
            dic.Add(key, value);
            return true;
        }

        public static bool AddOrReplaceKV<K, V>(this IDictionary<K, V> dic, KeyValuePair<K,V> kv)
        {
            return dic.AddOrReplaceKV(kv.Key, kv.Value);
        }

        public static bool AddOrReplaceKV<K, V>(this IDictionary<K, V> dic, IEnumerable<KeyValuePair<K, V>> kvs)
        {
            bool isAdd = false;
            foreach (var kv in kvs)
            {
                if (dic.AddOrReplaceKV(kv))
                {
                    isAdd = true;
                }
            }
            return isAdd;
        }


        /// <summary>
        /// 加入了新key的话返回true
        /// </summary>
        public static bool AddKeyWithDefault<K, V>(this IDictionary<K, V> dic, K key)
        {
            if (dic.ContainsKey(key)) return false;
            dic.Add(key,default);
            return true;
        }
        
        /// <summary>
        /// 加入了新key的话返回true
        /// </summary>
        public static bool AddKeyWithNew<K, V>(this IDictionary<K, V> dic, K key)where V:new()
        {
            if (dic.ContainsKey(key)) return false;
            dic.Add(key,new V());
            return true;
        }
        
        #endregion

        #region about get
        public static T GetValueOrDefault<K, T>(this IDictionary<K, T> dic, K key)
        {
            if (dic.TryGetValue(key, out var v))
            {
                return v;
            }
            return default;
        }

        /// <summary>
        /// 一定会返回key
        /// </summary>
        public static V GetValueOrCreatDefault<K, V>(this IDictionary<K, V> dic, K key)
        {
            if (dic.TryGetValue(key, out var v))
            {
                return v;
            }
            else
            {
                v = default;
                dic.Add(key, v);
                return v;
            }
        }

        /// <summary>
        /// 如果没有key，会返回false，不会创建默认值
        /// </summary>
        public static bool TryGetValueOrCreatDefaultOut<K, V>(this IDictionary<K, V> dic, K k, out V v)
        {
            if (dic.TryGetValue(k, out v))
            {
                if (v == null)
                {
                    v = default;
                    dic[k] = v;
                    return true;
                }
            }
            return false;
        }

        #endregion
        public static bool TrySetValue<K,V>(this IDictionary<K,V> dic,K key,V value)
        {
            if (dic.ContainsKey(key))
            {
                dic[key] = value;
                return true;
            }
            return false;
        }

        
    }
}
